/*
 * util.c - commonly used utility functions.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "table.h"

#if   defined(_MSC_VER) && (_MSC_VER>1000)
#pragma warning(disable:311)
#endif

bool debug = TRUE;

void *checked_malloc(int len)
{
    void *p = malloc(len);
     if (!p)
    {
        fprintf(stderr,"\nRan out of memory!\n");
        exit(1);
     }
     return p;
}

string String(char *s)
{
    string p = checked_malloc((int)strlen(s)+1);
     strcpy(p,s);
     return p;
}

U_boolList U_BoolList(bool head, U_boolList tail)
{
    U_boolList list = checked_malloc(sizeof(*list));
      list->head = head;
      list->tail = tail;
      return list;
}

typedef struct U_stackItem_ *U_stackItem;
struct U_stackItem_
{
    void* data;
    U_stackItem next;
};

struct U_stack_
{
    int count;
    U_stackItem top;
    U_stackItem bottom;
};

U_stack U_stackNew()
{
    U_stack p = checked_malloc(sizeof(*p));
    p->count = 0;
    p->top = p->bottom = NULL;
    return p;
};
void U_stackDestroy(U_stack stack)
{
    if (!stack)
        return;

    while(U_stackPop(stack))
        ;
    free(stack);
};

int U_stackPush(U_stack stack, void* data)
{
    U_stackItem item;
    if (!stack)
        return RESULT_ERROR;
    item = checked_malloc(sizeof(*item));
    item->next = stack->top;
    item->data = data;
    stack->top = item;
    stack->count ++;
    return RESULT_OK;
};
void* U_stackPop(U_stack stack)
{
    void* data;
    U_stackItem item;
    if (!stack || stack->count == 0)
        return NULL;
    item = stack->top;
    data = stack->top->data;
    stack->top = item->next;
    stack->count --;
    free(item);
    return data;
};

int U_stackCount(U_stack stack)
{
    return stack->count;
};

void U_stackForEach(U_stack stack, stackIterFunc f)
{
    U_stackItem item = stack->top;
    if (!f)
        return;
    while(item)
    {
        if (f(item->data) != RESULT_OK)
            return;
        item = item->next;
    }
};

U_stackIter U_stackGetIter(U_stack stack)
{
    return (U_stackIter)(&stack->top);
};

void U_stackWalk(U_stackIter* item)
{
    assert(item && *item);

    *item = (*item)->next;
};

void* U_stackLookup(U_stackIter item)
{
    return item->data;
};

#define U_nbListLen    128

struct U_nbListItem_
{
    int index;
    void *key;
};

struct U_nbList_
{
    int        count;
    bool    data[U_nbListLen][U_nbListLen];
    TAB_table ptr_index;
    TAB_table index_ptr;
};

void U_nbListClear(U_nbList l)
{
    int i, j;
    assert(l);
    l->ptr_index = l->index_ptr = NULL;
    l->count = 0;
    l->ptr_index = TAB_empty();
    l->index_ptr = TAB_empty();
    for (i=0; i< U_nbListLen; i++)
    {
        for (j=0; j<U_nbListLen; j++)
            l->data[i][j] = FALSE;
    }
}

U_nbList U_nbListNew()
{
    U_nbList p = checked_malloc(sizeof(*p));
    int i,j;

    p->ptr_index = p->index_ptr = NULL;

    p->count = 0;
    p->ptr_index = TAB_empty();
    p->index_ptr = TAB_empty();
    for (i=0; i< U_nbListLen; i++)
    {
        for (j=0; j<U_nbListLen; j++)
            p->data[i][j] = FALSE;
    }
    return p;
}

void U_nbListDestroy(U_nbList list)
{
    assert(list);
    free(list);
}

int U_nbListEnter(U_nbList list, U_nbListNode node)
{
    assert(list);
    list->count ++;
    TAB_enter(list->ptr_index, node, (void *)(list->count));
    TAB_enter(list->index_ptr, (void*)(list->count), node);
    return list->count;
}

void U_nbListAddEdge(U_nbList list, U_nbListNode n1, U_nbListNode n2)
{
    assert(list);
    
    int x1 = (int)TAB_look(list->ptr_index, n1);
    int x2 = (int)TAB_look(list->ptr_index, n2);

    if (!x1)
        x1 = U_nbListEnter(list, n1);
    if (!x2)
        x2 = U_nbListEnter(list, n2);

    assert(x1 < U_nbListLen && x2 < U_nbListLen);
    list->data[x1][x2] = TRUE;
}

bool U_nbListIsAdj(U_nbList list, U_nbListNode n1, U_nbListNode n2)
{
    assert(list);
    int x1 = (int)TAB_look(list->ptr_index, n1);
    int x2 = (int)TAB_look(list->ptr_index, n2);
    return list->data[x1][x2];
}

bool U_nbListIsAdjK(U_nbList list, int n1, int n2)
{
    assert(list);
    return list->data[n1][n2];
}

int U_nbListCount(U_nbList list)
{
    assert(list);
    return list->count;
}

int U_nbListGetKey(U_nbList list, U_nbListNode node)
{
    assert(list);
    return (int)TAB_look(list->ptr_index, node);
}

void* U_nbListGetPtr(U_nbList list, int key)
{
    assert(list);
    return TAB_look(list->index_ptr, (void*)key);
}

#define MAX_USET_ITEM 32

struct U_set_
{
    int count;
    void* data[32];
};

U_set U_setNew()
{
    int i;
    U_set p = checked_malloc(sizeof(*p));
    p->count = 0;
    for (i = 0; i < MAX_USET_ITEM; ++i)
        p->data[i] = NULL;
    return p;
}

void U_setDestroy(U_set* set)
{
    assert(set && *set);
    free(*set);
    *set = NULL;
}

bool U_setHas(U_set set, void* data)
{
    int i;

    assert(set);
    for (i = 0; i < set->count; ++i)
    {
        if(set->data[i] == data)
            return TRUE;
    }
    return FALSE;
}

int U_setInsert(U_set a, void* data)
{
    assert(a);
    if( !U_setHas(a, data) )
    {
        a->data[a->count] = data;
        a->count ++ ;
    }
}

int U_setRemove(U_set a, void* data)
{
    int i, j;
    bool removed =  FALSE;

    assert(a);
    for (i = 0; i < a->count; ++i)
    {
        if(a->data[i] == data)
        {
            for (j = i; j < a->count-1; ++j)
            {
                a->data[j] = a->data[j + 1];
            }
            a->count--;
            removed =  TRUE;
            break;
        }
    }
    return removed;
}

int U_setAdd2(U_set a, U_set b)
{
    int i;
    int count = 0;
    assert(a && b);
    for (i = 0; i < b->count; ++i)
    {
        if(!U_setHas(a, b->data[i]))
        {
            U_setInsert(a, b->data[i]);
            count ++ ;
        }
    }
    return count;
};

int U_setSub2(U_set a,  U_set b)
{
    assert(a && b);
    int i, count = 0;
    for (i = 0; i < b->count; ++i)
    {
        if( U_setRemove(a,  b->data[i]) )
        {
            ++ count;
        }
    }
    return count;
}

void U_setClear(U_set a)
{
    assert(a);
    a->count = 0;
}

void* U_setLookup(U_set a, int index)
{
    assert(a && index < a->count);
    if( index < a->count)
        return a->data[index];
}

int U_setGetCount(U_set s)
{
    assert(s);
    return s->count;
}
